package com.eric.uniqueid;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.eric.uniqueid.domain.Sequence;
import com.eric.uniqueid.service.ISequenceService;
import com.eric.uniqueid.service.impl.SequenceServiceImpl;

/**
 * @ClassName: SequenceIdUtils.java
 * @author liuq
 * @version V1.0
 * @Date 2019年11月8日 下午1:58:41 自增id生成 开发方式： 1.新增数据库表，一次执行以下sql #创建--Sequence 管理表 DROP TABLE IF EXISTS sequence; CREATE
 *       TABLE sequence ( name VARCHAR(50) NOT NULL, current_value INT NOT NULL, increment INT NOT NULL DEFAULT 1,
 *       PRIMARY KEY (name) ) ENGINE=InnoDB;
 * 
 *       #创建--取当前值的函数 DROP FUNCTION IF EXISTS currval; DELIMITER $ CREATE FUNCTION currval (seq_name VARCHAR(50))
 *       RETURNS INTEGER LANGUAGE SQL DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER COMMENT '' BEGIN DECLARE value
 *       INTEGER; SET value = 0; SELECT current_value INTO value FROM sequence WHERE name = seq_name; RETURN value; END
 *       $ DELIMITER ;
 * 
 *       #创建--取下一个值的函数 DROP FUNCTION IF EXISTS nextval; DELIMITER $ CREATE FUNCTION nextval (seq_name VARCHAR(50))
 *       RETURNS INTEGER LANGUAGE SQL DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER COMMENT '' BEGIN UPDATE sequence
 *       SET current_value = current_value + increment WHERE name = seq_name; RETURN currval(seq_name); END $ DELIMITER
 *       ;
 * 
 *       #创建--更新当前值的函数 DROP FUNCTION IF EXISTS setval; DELIMITER $ CREATE FUNCTION setval (seq_name VARCHAR(50), value
 *       INTEGER) RETURNS INTEGER LANGUAGE SQL DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER COMMENT '' BEGIN UPDATE
 *       sequence SET current_value = value WHERE name = seq_name; RETURN currval(seq_name); END $ DELIMITER ;
 * 
 *       测试 #添加一个sequence名称和初始值，以及自增幅度 INSERT INTO sequence VALUES ('TestSeq', 0, 1); SELECT SETVAL('TestSeq',
 *       10);#设置指定sequence的初始值 SELECT CURRVAL('TestSeq');#查询指定sequence的当前值 SELECT NEXTVAL('TestSeq');#查询指定sequence的下一个值
 *       Delete from sequence;#清空表
 * 
 *       1.在sequence.properties配置文件中配置序列ID 属性：sequenceID.name 值：id1,id2,id3.....
 *       例：sequenceID.name=seqID1，seqid2,seqid3.... 2.配置每个序列id的属性（初始值，每次增长大小） 例： #设置seqID1初始值
 *       sequenceID.name.currentValue.seqID1=0 #设置seqID1每次增长值 sequenceID.name.increment.seqID1=1 #设置seqid2初始值
 *       sequenceID.name.currentValue.seqid2=1 #设置seqid2每次增长值 sequenceID.name.increment.seqid2=2
 *       3.springboot项目中扫描dao层，service层.. 启动类添加注解 @MapperScan("com.liu.*")
 *       //扫描dao层（必须配置，不然无法找到mapper.xml文件） @ComponentScan({"com.liu.*"})
 * 
 *       4.使用方式 （1）在resources目录下新建sequence.properties （2）在sequence.properties中配置id
 *       例：sequenceID.name=seq_sys_user,seq_sys_role, #设置初始值 sequenceID.name.currentValue.seq_sys_user=0 #设置每次增长值
 *       sequenceID.name.increment.seq_sys_user=1 #设置初始值 sequenceID.name.currentValue.seq_sys_role=0 #设置每次增长值
 *       sequenceID.name.increment.seq_sys_role=1 （3）程序中调用 SequenceIdUtils sequenceId = new SequenceIdUtils(); String
 *       sequenceid = sequenceId.createNextId(2, "seq_sys_user");
 */

@Component
public class SequenceIdUtils {

    private static final Logger logger = LoggerFactory.getLogger(SequenceIdUtils.class);

    private ISequenceService iSequenceService =
        (ISequenceService)ApplicationContextProvider.getBean(SequenceServiceImpl.class);

    @PostConstruct
    public void init() {

        logger.info(">>>>>>Init sequenceId [begin] ");
        try {
            // 校验数据库表是否存在
            int i = iSequenceService.existTable("sequence");
            if (i <= 0) {// 数据库表不存在
                // 建表
                iSequenceService.createSequence();
                iSequenceService.createCurrval();
                iSequenceService.createNextval();
                iSequenceService.createSetval();
            }

            // 初始化
            String seqid = "";
            Properties properties = new Properties();
            URL url = SequenceIdUtils.class.getClassLoader().getResource("sequence.properties");
            if (url != null) {
                // 获取application.yaml文件中的配置数据，然后转换为obj，
                properties.load(new FileInputStream(url.getFile()));
                seqid = (String)properties.getProperty("sequenceID.name");
                String[] requenceID = seqid.split(",");
                // 清空数据库表
                Sequence sequence1 = new Sequence();
                iSequenceService.deleteAll(sequence1);
                if (seqid != null && seqid.length() != 0) {
                    for (String sequenceid : requenceID) {
                        Sequence sequence = new Sequence();
                        sequence.setName(sequenceid.trim());
                        String currentValue =
                            (String)properties.getProperty("sequenceID.name.currentValue." + sequenceid);
                        if (currentValue != null && currentValue.length() != 0) {
                            currentValue = "0";// 初始值
                        }
                        sequence.setCurrentValue(Integer.parseInt(currentValue));
                        String increment = (String)properties.getProperty("sequenceID.name.increment." + sequenceid);
                        if (increment != null && increment.length() != 0) {
                            increment = "1";// 初始值
                        }
                        sequence.setIncrement(Integer.parseInt(increment));

                        iSequenceService.insert(sequence);
                    }
                }
            } else {
                logger.error(">>>>>>未找到sequence.properties文件");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.info(">>>>>>Init SequenceId [end] ");
    }

    /**
     * 生成自增序号
     * 
     * @param size
     *            序列长度
     * @param sequenceID
     *            序列ID
     * @return
     */
    public String createNextId(int size, String sequenceID) {
        Sequence sequence = new Sequence();
        sequence.setName(sequenceID);
        int count = 0;

        try {
            count = iSequenceService.nextVal(sequence);
            if (String.valueOf(count + 1).length() > size) {
                initSequence(sequenceID);// 初始化单条id
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        String createId = new String();
        for (int i = 0; i < size - String.valueOf(count).length(); i++) {
            createId += "0";
        }
        return String.valueOf(createId) + String.valueOf(count);
    }

    public void initSequence(String sequenceID) {
        String seqid = "";
        Properties properties = new Properties();
        URL url = SequenceIdUtils.class.getClassLoader().getResource("sequence.properties");
        if (url != null) {
            // 获取application.properties文件中的配置数据，然后转换为obj，
            try {
                properties.load(new FileInputStream(url.getFile()));
                seqid = sequenceID;
                if (seqid != null && seqid.length() != 0) {
                    Sequence sequence = new Sequence();
                    sequence.setName(seqid.trim());
                    String currentValue = (String)properties.getProperty("sequenceID.name.currentValue." + seqid);
                    if (currentValue != null && currentValue.length() != 0) {
                        currentValue = "0";// 初始值
                    }
                    sequence.setCurrentValue(Integer.valueOf(currentValue));
                    String increment = (String)properties.getProperty("sequenceID.name.increment." + seqid);
                    if (increment != null && increment.length() != 0) {
                        increment = "1";// 初始值
                    }
                    sequence.setIncrement(Integer.valueOf(increment));

                    iSequenceService.update(sequence);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            logger.error(">>>>>>未找到sequence.properties文件");
        }
    }
}
